﻿#include "Matrix.h"
#include "Constant.h"
#include "CoordSys.h"
#include "TimeSys.h"
#include "ReadN.h"
#include "ReadO.h"
#include "GNSSSatPos.h"
#include "IonoCorr.h"
#include "TropCorr.h"
#include "SPP.h"
#include <iostream>
#include <iomanip>
#include <vector>
#include <cstdlib> /*用于使用语句 system("pause");*/
using namespace std;

/* 用于测试类 */
int main() {
    /* 测试常数类 */
    GNSSconsts* pGnssConst;
    BDSConsts bdsConst;
    pGnssConst = &bdsConst; /* 用法：基类指针指向派生类实例化对象 */
    cout << fixed << pGnssConst->get_refEllip().f << endl;

    /* 测试矩阵类 */
    cout << "/* 测试矩阵类 */" << endl;
    Matrix matTest;
    matTest.test();

    /* 测试坐标系统类 */
    cout << "/* 测试坐标系统类 */" << endl;
    CoordSys* pCoordSys;
    BDCS bdcs(bdsConst.get_refEllip());
    pCoordSys = &bdcs;
    pCoordSys->test();

    /* 测试时间系统类 */
    cout << "/* 测试时间系统类 */" << endl;
    CalendT t = { 2016,7,14,1,0,0 };/* N 文件中第一个星历的时间，对应BDS 549周， 349200秒 */
    BDSTime mBDST;
    TimeSys* pTimeSys = &mBDST;
    pTimeSys->print_time(t);
    cout << " 对应的BDS时间为：" << endl;
    SOW t2 = pTimeSys->calend2sow(t);
    pTimeSys->print_time(t2);

    /* 测试 Read N 文件类 */
    ReadN mReadN("1234560660442.17N");
    if (!mReadN.parseFile()) return false;
    if (!mReadN.print_eph()) return false;

    /* 测试 Read O 文件类 */
    string filename = "1234560660442.17O";// 声明要读取的文件名   
    ReadO mReadO(filename);  // 创建 ReadO 对象
    if (!mReadO.parse_file()) return false;
    mReadO.print_head();// 显示文件头部信息
    mReadO.print_body(2);// 显示前 10 个历元的观测数据
    vector<obsEpoch>* mObs = mReadO.get_obs();
    BaseT tr;
    tr = pTimeSys->str2baseT(mObs->at(0).time); // 获取O文件中第一次观测的的时间

    /* 测试卫星位置计算类 */
    cout << "/* 卫星位置计算类 */" << endl;
    GNSSSatPos* pSatPos;
    BDSSatPos mBDSSatPos(pTimeSys, &mReadN);
    pSatPos = &mBDSSatPos; /* 用法：基类指针指向派生类实例化对象 */
    XYZ ps1;
    ps1 = pSatPos->get_satPos("C01", tr);
    printf("C01 卫星位置：X=%.3f m, Y=%.3f m, Z=%.3f m\n\n", ps1.x, ps1.y, ps1.z);

    /* 电离层延迟误差改正 */
    cout << "/*电离层延迟误差改正类 */" << endl;
    IonoCorr mIonCor(pGnssConst, &mReadN.get_head());
    CalendT tObs = { 2017, 3, 7, 5, 6, 35,0.00 };
    SOW sow = pTimeSys->calend2sow(tObs);

    XYZ rr = { -2091342.6543,4800418.4462,3629758.3665 }; /* 接收机坐标概况值 */
    BLH blh = pCoordSys->XYZ2BLH(rr);         /* 接收机大地坐标 */
    Azel azel = pCoordSys->get_azel(rr, ps1); /* 计算接收机到卫星的方位角和高度角 */
    double ionCor = mIonCor.get_ionoCorr(blh, azel, sow);
    cout << fixed << ionCor << endl << endl;

    /* 对流层延迟误差改正 */
    cout << "/*对流层延迟误差改正类 */" << endl;
    TropCorr mTropCor(pGnssConst);
    double tropCor = mTropCor.get_tropCorr(blh, azel.ele);
    cout << fixed << tropCor << endl << endl;

    // 单点定位计算
    SPPSolver singleSPP(&bdcs, &mBDSSatPos, &mIonCor, &mTropCor, &mReadO, &mReadN, pTimeSys);

    // 设置初始位置
    XYZ receiverPosition = { 0, 0, 0 };
    double clockError = 0;

    // 处理第一个历元
    if (singleSPP.solve_epoch(0, receiverPosition, clockError)) {
        cout << "定位结果: \n"
            << "X: " << receiverPosition.x << " m\n"
            << "Y: " << receiverPosition.y << " m\n"
            << "Z: " << receiverPosition.z << " m\n";
    }
    else {
        cerr << "定位失败" << endl;
    }
    return 0;
}

/*
 * GNSS单点定位全流程说明
 *
 * 1. 系统初始化阶段
 *    - 创建并初始化时间系统对象(BDSTime)
 *    - 创建并初始化坐标系统对象(BDCS)
 *    - 创建观测文件读取器(ReadO)和导航文件读取器(ReadN)
 *    - 创建卫星位置计算器(BDSSatPos)
 *    - 创建误差改正器(IonoCorr和TropCorr)
 *
 * 2. 数据准备阶段
 *    - 使用ReadN解析导航文件(N文件)，获取卫星星历数据
 *    - 使用ReadO解析观测文件(O文件)，获取伪距观测数据
 *    - 验证文件解析是否成功
 *
 * 3. 单点定位处理器创建
 *    - 创建SPPSolver对象，传入所有必要的组件
 *      (坐标系统、卫星位置计算器、误差改正器、文件读取器等)
 *
 * 4. 历元数据处理阶段(对每个历元执行以下步骤)
 *    a. 数据获取
 *       - 从观测数据中获取当前历元的观测值
 *       - 获取卫星ID和对应的伪距观测值
 *
 *    b. 初始位置设置
 *       - 首次定位使用零值或概略位置作为初始值
 *       - 后续历元可使用前一次定位结果作为初始值
 *
 *    c. 迭代计算(最多MAX_ITERATIONS次)
 *       - 计算每颗卫星的位置和钟差(使用广播星历)
 *       - 计算接收机与卫星之间的几何距离
 *       - 计算电离层和对流层延迟改正量
 *       - 构建设计矩阵(方向余弦)和观测向量(伪距残差)
 *       - 使用最小二乘法求解位置和钟差增量
 *       - 更新接收机位置和钟差估计值
 *       - 检查位置增量是否小于收敛阈值
 *
 *    d. 结果输出
 *       - 输出最终定位结果(ECEF坐标系XYZ)
 *       - 将结果转换为大地坐标(BLH)
 *       - 输出接收机钟差(距离单位)
 *
 * 5. 结束处理
 *    - 释放所有资源
 *    - 输出定位精度评估结果(如可用)
 */

